package com.net.xpay.admin.controller.admin;

import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayFundAccountbookNotifySubscribeResponse;
import com.alipay.api.response.AlipayFundTransCommonQueryResponse;
import com.alipay.api.response.AlipayUserAgreementQueryResponse;
import com.google.common.base.Preconditions;
import com.net.common.model.ResultData;
import com.net.common.util.LocalDateUtil;
import com.net.common.util.MoneyUtil;
import com.net.xpay.alipay.safePay.PoseidonSafePayAlipayClient;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.common.model.search.UserSearchModel;
import com.net.xpay.core.domain.UserAccount;
import com.net.xpay.core.enums.AccountBillType;
import com.net.xpay.core.enums.AccountFundType;
import com.net.xpay.core.manager.AccountLogManager;
import com.net.xpay.core.manager.UserAccountManager;
import com.net.xpay.core.model.AccountLogSearchModel;
import com.net.shard.ShardDataSource;
import com.net.shard.ShardDataSourceConfigurer;
import com.net.shard.ShardUtil;
import com.net.shard.domain.ShardConfig;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 2020/9/17 14:46

 * 把接口暴露出去给自己的系统使用
 */
@RestController
@Slf4j
@RequestMapping("/admin/test")
@Api(tags = "第三方开放调用/支付宝接口", description = "第三方开放调用 支付宝接口 net")
public class AdminTestApiController {

    @Autowired
    private PoseidonSafePayAlipayClient xpaySafePayAlipayClient;

    @Autowired
    private UserManager userManager;

    @Autowired
    private UserShardManager userShardManager;

    @Autowired
    private UserAccountManager userAccountManager;

    @Autowired
    private AccountLogManager accountLogManager;

    @Autowired
    @Qualifier("shardDataSource")
    private DataSource shardDataSource;

    //签约结果查询
    @ApiOperation(value = "签约结果查询")
    @PostMapping("/query-sign-result")
    @ResponseBody
    public ResultData<AlipayUserAgreementQueryResponse> querySignResult(String externalNo) throws AlipayApiException {
        return new ResultData<>(xpaySafePayAlipayClient.alipayUserAgreementQuery(externalNo));
    }
/**/


    @ApiOperation(value = "订阅入金")
    @PostMapping("/subscribe-book")
    @ResponseBody
    public ResultData<AlipayFundAccountbookNotifySubscribeResponse> subscribe(String bookId, String agreeNo) throws AlipayApiException {
        AlipayFundAccountbookNotifySubscribeResponse resp = xpaySafePayAlipayClient.alipayFundAccountbookNotifySubscribe(bookId, agreeNo);
        return new ResultData<>(resp);
    }


    //查询转账结果
    @ApiOperation(value = "查询转账结果")
    @PostMapping("/query-alipay-trans-result")
    @ResponseBody
    public ResultData<AlipayFundTransCommonQueryResponse> queryBank(String outBizNo) throws AlipayApiException {
        AlipayFundTransCommonQueryResponse resp = xpaySafePayAlipayClient.queryTransferAlipayFundTrans(outBizNo);
        return new ResultData<>(resp);
    }

    @ApiOperation(value = "查询余额2")
    @PostMapping("/query-balance2")
    @ResponseBody
    public ResultData<String> queryBalance2() throws AlipayApiException {
        List<Long> userIds = userManager.listIds(new UserSearchModel());
        Long balance = 0L;
        for (Long userId : userIds) {
            UserShard userShard = userShardManager.getById(userId);
            try {
                ShardUtil.setShardContext(userShard.getShardId());
                UserAccount userAccount = userAccountManager.getById(userId);
                balance += userAccount.getMoneyLeft();
            } finally {
                ShardUtil.cleanShardContext();
            }


        }
        return new ResultData<>(MoneyUtil.convertCentToString(balance, 2));
    }


    @ApiOperation(value = "检查支出")
    @PostMapping("/check-money-left")
    @ResponseBody
    public ResultData<Object> queryBalance(String startTime, String endTime) throws AlipayApiException {
        LocalDateTime minCreateTime = LocalDateUtil.parseStringToDateTime(startTime);
        LocalDateTime maxCreateTime = LocalDateUtil.parseStringToDateTime(endTime);

        //2月4号以后才能保证有完整的数据
        ShardDataSourceConfigurer shardDataSourceConfigurer = ((ShardDataSource) shardDataSource).getShardDataSourceConfigurer();
        Map<Long, ShardConfig> shardConfigMap = shardDataSourceConfigurer.getShardConfigMap();
        Preconditions.checkArgument(CollectionUtils.isNotEmpty(shardConfigMap.keySet()));

        //先查出每个商户最后一条的和第一条的
        //分库
        long totalAfterAmount = 0L;
        long totalBeforeAmount = 0L;
        long totalCheckCodeFee = 0L;
        long totalWithDrawFee = 0L;
        long totalChargeFee = 0L;
        long totalChange = 0L;

        long totalSafePayOutChange = 0L;
        long totalSafePayRefund = 0L;

        long totalPayTransOutChange = 0L;
        long totalPayTransRefund = 0L;

        for (Long shardId : shardConfigMap.keySet()) {
            try {
                ShardUtil.setShardContext(shardId);
                long afterAmount = accountLogManager.sumLastAfterAmountByTime(minCreateTime, maxCreateTime);
                totalAfterAmount += afterAmount;

                long beforeAmount = accountLogManager.sumFirstBeforeAmountByTime(minCreateTime, maxCreateTime);
                totalBeforeAmount += beforeAmount;

                AccountLogSearchModel searchModel = new AccountLogSearchModel();
                searchModel.setCreateMinTime(minCreateTime);
                searchModel.setCreateMaxTime(maxCreateTime);
                searchModel.setAccountFundType(AccountFundType.MONEY);
                searchModel.setType(AccountBillType.CHECK_CODE);

                long checkCodeFee = accountLogManager.sumAccountLog(searchModel);
                totalCheckCodeFee += checkCodeFee;

                searchModel = new AccountLogSearchModel();
                searchModel.setCreateMinTime(minCreateTime);
                searchModel.setCreateMaxTime(maxCreateTime);
                searchModel.setAccountFundType(AccountFundType.MONEY);
                searchModel.setType(AccountBillType.USER_WITHDRAW_REFUND);

                long withDrawFee = accountLogManager.sumAccountLog(searchModel);
                totalWithDrawFee += withDrawFee;

                searchModel = new AccountLogSearchModel();
                searchModel.setType(AccountBillType.CHARGE);
                searchModel.setAccountFundType(AccountFundType.MONEY);
                searchModel.setCreateMinTime(minCreateTime);
                searchModel.setCreateMaxTime(maxCreateTime);

                long chargeFee = accountLogManager.sumAccountLog(searchModel);
                totalChargeFee += chargeFee;

                searchModel = new AccountLogSearchModel();
                searchModel.setAccountFundType(AccountFundType.MONEY);
                searchModel.setCreateMinTime(minCreateTime);
                searchModel.setCreateMaxTime(maxCreateTime);
                long changeFee = accountLogManager.sumAccountLog(searchModel);
                totalChange += changeFee;


                searchModel = new AccountLogSearchModel();
                searchModel.setType(AccountBillType.SAFE_PAY_TRANS_SERVICE_PRICE);
                searchModel.setAccountFundType(AccountFundType.MONEY);
                searchModel.setCreateMinTime(minCreateTime);
                searchModel.setCreateMaxTime(maxCreateTime);
                long safePayOutChange = accountLogManager.sumAccountLog(searchModel);
                totalSafePayOutChange += safePayOutChange;


                searchModel = new AccountLogSearchModel();
                searchModel.setType(AccountBillType.SAFE_PAY_TRANS_SERVICE_PRICE_REFUND);
                searchModel.setAccountFundType(AccountFundType.MONEY);
                searchModel.setCreateMinTime(minCreateTime);
                searchModel.setCreateMaxTime(maxCreateTime);
                long safePayRefund = accountLogManager.sumAccountLog(searchModel);
                totalSafePayRefund += safePayRefund;


                searchModel = new AccountLogSearchModel();
                searchModel.setType(AccountBillType.PAY_TRANS_SERVICE_PRICE);
                searchModel.setAccountFundType(AccountFundType.MONEY);
                searchModel.setCreateMinTime(minCreateTime);
                searchModel.setCreateMaxTime(maxCreateTime);
                long payTransOutChange = accountLogManager.sumAccountLog(searchModel);
                totalPayTransOutChange += payTransOutChange;


                searchModel = new AccountLogSearchModel();
                searchModel.setType(AccountBillType.PAY_TRANS_SERVICE_PRICE_REFUND);
                searchModel.setAccountFundType(AccountFundType.MONEY);
                searchModel.setCreateMinTime(minCreateTime);
                searchModel.setCreateMaxTime(maxCreateTime);
                long payTransRefund = accountLogManager.sumAccountLog(searchModel);
                totalPayTransRefund += payTransRefund;

                log.info("shardId={}|beforeAmount={}|afterAmount={}|checkCodeFee={}|chargeFee={}|changeFee={}", shardId, beforeAmount, afterAmount, checkCodeFee, chargeFee, changeFee);
            } finally {
                ShardUtil.cleanShardContext();
            }
        }

        Map<String, String> ret = new HashMap<>();
        ret.put("beforeAmount", MoneyUtil.convertCentToString(totalBeforeAmount, 2));
        ret.put("afterAmount", MoneyUtil.convertCentToString(totalAfterAmount, 2));
        ret.put("change", MoneyUtil.convertCentToString(totalAfterAmount - totalBeforeAmount, 2));

        ret.put("totalCheckCodeFee", MoneyUtil.convertCentToString(totalCheckCodeFee, 2));
        ret.put("totalWithDrawFee", MoneyUtil.convertCentToString(totalWithDrawFee, 2));
        ret.put("totalChargeFee", MoneyUtil.convertCentToString(totalChargeFee, 2));

        ret.put("totalChange", MoneyUtil.convertCentToString(totalChange, 2));

        ret.put("totalSafePayOutChange", MoneyUtil.convertCentToString(totalSafePayOutChange, 2));
        ret.put("totalSafePayRefund", MoneyUtil.convertCentToString(totalSafePayRefund, 2));
        ret.put("totalSafePayChange", MoneyUtil.convertCentToString(totalSafePayOutChange + totalSafePayRefund, 2));

        ret.put("totalPayTransOutChange", MoneyUtil.convertCentToString(totalPayTransOutChange, 2));
        ret.put("totalPayTransRefund", MoneyUtil.convertCentToString(totalPayTransRefund, 2));
        ret.put("totalPayTransChange", MoneyUtil.convertCentToString(totalPayTransOutChange + totalPayTransRefund, 2));

        return new ResultData<>(ret);
    }


}
